package net.lwf.exception;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.log4j.Logger;


public class ExceptionUtil {
	
	public static void logException(Class<?> clazz, AppException e) {
		if (!e.isLogged()) {
			Logger log = Logger.getLogger(clazz);
			log.error(e.getUniqueID(), e);
			e.setLogged();
		}
	}
	
	public static void logAndThrowException(Class<?> clazz, String message) {
		AppException appex = new AppException(message);
		logAndThrowException(clazz, appex);
	}
	
	public static void logAndThrowException(Class<?> clazz, Exception ex) {
		logAndThrowException("", clazz, ex);
	}
	
	/*public static void logAndThrowException(String message, Class<?> clazz, Exception ex) {
		AppException appex = new AppException(ex, message);
		logException(clazz, appex);
		throw appex;
	}
	
	public static void logAndThrowException(Class<?> clazz, Throwable throwable) {
		
		AppException appex = null;
		if(throwable instanceof AppException) {
			appex = (AppException) throwable;
		}
		else {
			appex = new AppException(throwable.getCause());
			logException(clazz, appex);
			Logger log = Logger.getLogger(clazz);
			log.error(joinStackTrace(throwable.getCause()));
		}
		throw appex;
	}*/
	
	public static void logAndThrowException(String message, Class<?> clazz, Throwable throwable) {
		Logger log = Logger.getLogger(clazz);
		if(message != null && message.trim().length() != 0) {
			log.error(message);
		}
		logAndThrowException(clazz, throwable);
	}
	
	public static void logAndThrowException(Class<?> clazz, Throwable throwable) {
		throw logAndCreateAppException(clazz, throwable);
	}	
	
	public static AppException logException(Class<?> clazz, Throwable throwable) {
		return logAndCreateAppException(clazz, throwable);
	}

	private static AppException logAndCreateAppException(Class<?> clazz,
			Throwable throwable) {
		AppException appex = null;
		if(throwable instanceof AppException) {
			appex = (AppException) throwable;
		}
		else {
			appex = new AppException(throwable.getCause());
		}
		logException(clazz, appex);
		Logger log = Logger.getLogger(clazz);
		log.error(joinStackTrace(throwable));
		return appex;
	}
	
	private static String joinStackTrace(Throwable e) {
	    StringWriter writer = null;
	    try {
	        writer = new StringWriter();
	        joinStackTrace(e, writer);
	        return writer.toString();
	    }
	    finally {
	        if (writer != null)
	            try {
	                writer.close();
	            } catch (IOException e1) {
	                // ignore
	            }
	    }
	}
	
	private static void joinStackTrace(Throwable e, StringWriter writer) {
	    PrintWriter printer = null;
	    try {
	        printer = new PrintWriter(writer);

	        while (e != null) {

	            printer.println(e);
	            StackTraceElement[] trace = e.getStackTrace();
	            for (int i = 0; i < trace.length; i++)
	                printer.println("\tat " + trace[i]);

	            e = e.getCause();
	            if (e != null)
	                printer.println("Caused by:\r\n");
	        }
	    }
	    finally {
	        if (printer != null)
	            printer.close();
	    }
	}
}
